<template>
  <div class="hs-map" id="hs-map-container" :style="styles" ref="mapContainer"></div>
</template>

<script setup>
import { computed, nextTick, ref, watch } from 'vue'
import mapApi from './api'
import _ from 'lodash'
const mapContainer = ref()
const emit = defineEmits()
const props = defineProps({
  modelValue: {
    type: Object,
    default: () => ({
      address: '',
      lng: '',
      lat: '',
    }),
  },
  styles: {
    type: Object,
    default: () => ({
      height: '200px',
      width: 'inherit',
    }),
  },
  zoom: {
    type: Number,
    default: 18,
  },
  enableScrollWheelZoom: {
    type: Boolean,
    default: true,
  },
})

let map = null

let lng = ref(props.modelValue.lng)
let lat = ref(props.modelValue.lat)
let address = ref(props.modelValue.address)
const _lng = computed({
  get() {
    return lng.value
  },
  set(v) {
    lng.value = v
    updateModelValue()
  },
})
const _lat = computed({
  get() {
    return lat.value
  },
  set(v) {
    lat.value = v
    updateModelValue()
  },
})
const _address = computed({
  get() {
    return address.value
  },
  set(v) {
    address.value = v
    updateModelValue()
  },
})

const updateModelValue = () => {
  emit('update:modelValue', {
    address: address.value,
    lng: lng.value,
    lat: lat.value,
  })
}

mapApi.loaded(async (BMapGl) => {
  await nextTick()
  map = new BMapGl.Map(mapContainer.value)
  props.enableScrollWheelZoom && map.enableScrollWheelZoom()
  await formatData()
  const point = new BMapGl.Point(_lng.value, _lat.value)
  map.centerAndZoom(point, props.zoom)
  map.addOverlay(new BMapGL.Marker(point, { title: _address.value }))
  map.addEventListener('click', (e) => {
    updatePoint(e.latlng)
  })
})

const formatData = async (partial) => {
  console.log('formatData')
  const hasPoint = !!(_lng.value && _lat.value)
  const hasAddress = !!_address.value
  if (!['point', 'address'].includes(partial)) {
    partial = hasPoint ? 'point' : hasAddress ? 'address' : 'point'
  }
  if (hasPoint || hasAddress) {
    if (hasPoint && partial === 'point') {
      _address.value = await mapApi.decode(_lng.value, _lat.value)
    } else if (hasAddress && partial === 'address') {
      const { lng, lat } = await mapApi.encode(_address.value)
      _lng.value = lng
      _lat.value = lat
    }
  } else {
    _lng.value = 116.404
    _lat.value = 39.915
    await formatData()
  }
}

const updatePoint = async ({ lng = _lng.value, lat = _lat.value } = point) => {
  _lng.value = lng
  _lat.value = lat
  await formatData('point')
  mapApi.loaded(async (BMapGl) => {
    const point = new BMapGl.Point(_lng.value, _lat.value)
    map.clearOverlays()
    map.centerAndZoom(point, props.zoom)
    map.addOverlay(new BMapGL.Marker(point, { title: _address.value }))
  })
}

const updateAddress = async (address) => {
  _address.value = address
  await formatData('address')
  mapApi.loaded(async (BMapGl) => {
    const point = new BMapGl.Point(_lng.value, _lat.value)
    map.clearOverlays()
    map.centerAndZoom(point, props.zoom)
    map.addOverlay(new BMapGL.Marker(point, { title: _address.value }))
  })
}

defineExpose({
  map,
  updateAddress,
  updatePoint,
})
</script>

<script>
export default {
  name: 'hs-map',
}
</script>

<style lang="scss">
.hs-map {
  .BMap_cpyCtrl {
    display: none;
  }
}
</style>
